#ifndef P2P_BASE_TURNSERVER_H_
#define P2P_BASE_TURNSERVER_H_

#include <map>

#include "base/sigslot.h"
#include "base/socketaddress.h"
#include "portinterface.h"

namespace base
{
	class AsyncPacketSocket;
	class ByteBuffer;
	class PacketSocketFactory;
	class Thread;
}

namespace cricket
{
	class StunMessage;
	class TurnMessage;

	// The default server port for TURN, as specified in RFC5766
	const int TURN_SERVER_PORT = 3478;

	// An interface through which the MD5 credential hash can be retrieved.
	class TurnAuthInterface
	{
	public:
		// Gets HA1 for the specified user and realm.
		// HA1 = MD5(HA1) = MD5(username:realm:password).
		// return true if the given username and realm are valid, or false if not.
		virtual bool GetKey(const std::string& username, const std::string& realm,
			std::string* key) = 0;
	};

	// The core TURN server class. Give it a socket to listen on via
	// AddInternalServerSocket, and a factory to create external sockets via
	// SetExternalSocketFactory, and it's ready to go.
	// Not yet wired up: TCP support.
	class TurnServer : public sigslot::has_slots<>
	{
	public:

	private:
		// Encapsulates the client's connection to the server.
		class Connection
		{
		public:
			Connection() : proto_(PROTO_UDP), socket_(NULL) {}
			Connection(const base::SocketAddress& src, 
				ProtocolType proto, base::AsyncPacketSocket* socket);

			const base::SocketAddress& src() const { return src_; }
			base::AsyncPacketSocket* socket() { return socket_; }
			bool operator==(const Connection& t) const;
			bool operator<(const Connection& t) const;

			std::string ToString() const;
		private:
			base::SocketAddress src_;
			base::SocketAddress dst_;
			cricket::ProtocolType proto_;
			base::AsyncPacketSocket* socket_;
		};
		class Allocation;
		class Permission;
		class Channel;
		typedef std::map<Connection, Allocation*> AllocationMap;


		typedef std::map<base::AsyncPacketSocket*, ProtocolType> InternalSocketMap;
		typedef std::map<base::AsyncSocket*, ProtocolType> ServerSocketMap;

		base::Thread* thread_;
		std::string nonce_key_;
		std::string realm_;
		std::string software_;
		TurnAuthInterface* auth_hook_;
		// otu - one-time-use. Server will respond with 438 if it's
		// sees the same nonce in next transaction.
		bool enable_otu_nonce_;
		InternalSocketMap server_sockets_;
		ServerSocketMap server_listen_sockets_;
		base::scoped_ptr<base::PacketSocketFactory> external_socket_factory_;
		base::SocketAddress external_addr_;
		AllocationMap allocations_;
	};
}

#endif	// P2P_BASE_TURNSERVER_H_